package cn.shengchao.config.mybatis;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.shengchao.base.anotation.DistributeDataPermission;
import cn.shengchao.examstar.rpc.distribute.enums.DistributeContentRoleEnum;
import cn.shengchao.examstar.rpc.distribute.enums.DistributeSaleRoleEnum;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
import lombok.SneakyThrows;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.*;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.ParenthesedSelect;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.SelectItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.continew.admin.common.userContext.UserDistributeContext;
import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.data.core.enums.DatabaseType;
import top.continew.starter.data.core.util.MetaUtils;
import top.continew.starter.extension.datapermission.annotation.DataPermission;
import top.continew.starter.extension.datapermission.filter.DataPermissionUserContextProvider;
import top.continew.starter.extension.datapermission.model.RoleContext;
import top.continew.starter.extension.datapermission.model.UserContext;

import javax.sql.DataSource;
import java.lang.reflect.Method;
import java.util.Collections;

/**
 * @program: examstarapi
 * @description: 分销用户角色数据过滤处理
 * @author: Xiong weiqiang
 * @create: 2025-05-26 16:49
 */
public class DistributeDataPermissionHandler implements DataPermissionHandler {

    private static final Logger log = LoggerFactory.getLogger(DistributeDataPermissionHandler.class);
    private final DataPermissionUserContextProvider dataPermissionUserContextProvider;
    private static final DataSource dataSource = SpringUtil.getBean(DataSource.class);

    public DistributeDataPermissionHandler(DataPermissionUserContextProvider dataPermissionUserContextProvider) {
        this.dataPermissionUserContextProvider = dataPermissionUserContextProvider;
    }

    @Override
    public Expression getSqlSegment(Expression where, String mappedStatementId) {
        try {
            Class<?> clazz = Class.forName(mappedStatementId.substring(0, mappedStatementId
                    .lastIndexOf(StringConstants.DOT)));
            String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(StringConstants.DOT) + 1);
            Method[] methodArr = clazz.getMethods();
            for (Method method : methodArr) {
                DistributeDataPermission dataPermission = method.getAnnotation(DistributeDataPermission.class);
                String name = method.getName();
                if (null == dataPermission || !CharSequenceUtil.equalsAny(methodName, name, name + "_COUNT")) {
                    continue;
                }
                if (dataPermissionUserContextProvider.isFilter()) {
                    return buildDataScopeFilter(dataPermission, where);
                }
            }
        } catch (ClassNotFoundException e) {
            log.error("Data permission handler build data scope filter occurred an error: {}.", e.getMessage(), e);
        }
        return where;
    }

    /**
     * 构建数据范围过滤条件
     *
     * @param dataPermission 数据权限
     * @param where          当前查询条件
     * @return 构建后查询条件
     */
    @SneakyThrows
    private Expression buildDataScopeFilter(DistributeDataPermission dataPermission, Expression where) {
        Expression expression = null;
        UserDistributeContext userContext = (UserDistributeContext)dataPermissionUserContextProvider.getUserContext();
        System.out.println("数据权限拦截正在发挥作用:");
        if (userContext!=null){
            //如果推广分销角色
            if (dataPermission.distributeType()!=null&&dataPermission.distributeType().equals("2")&& StrUtil.isNotBlank(userContext.getDistributeSaleRoleCode())){
                System.out.println("推广分销================================================:");
                DistributeSaleRoleEnum distributeSaleRoleEnum = DistributeSaleRoleEnum.getByCode(userContext.getDistributeSaleRoleCode());
                if (distributeSaleRoleEnum!=null){
                    switch (dataPermission.dataScope()) {
                        case ALL -> expression = where;
                        //分销用户有市场经理，加盟商、会员、员工，能看的学员查询过滤不一样
                        case SALE_INVITE_USER -> {
                            System.out.println("数据权限拦截SALE_INVITE_USER:");
                            String appendSqlStr="";
                            if (distributeSaleRoleEnum.equals(DistributeSaleRoleEnum.ROLE_DSPD)){
                                appendSqlStr = dataPermission.inviteTableAlias()  + ".invite_user_id" + " IN ( select user_id from distribute_dept_user_role_bind durb_x where dept_id in " +
                                        "(select DISTINCT a_x.dept_id from distribute_dept_info a_x " +
                                        "left join distribute_dept_user_role_bind b_x on a_x.dept_id=b_x.dept_id " +
                                        "where a_x.data_status=1 and b_x.data_status=1 and a_x.distribute_type=2 and (a_x.up_level_user_id="+userContext.getUserId() +" or a_x.dept_owner_id="+userContext.getUserId()+")))";
                            }else {
                                appendSqlStr = dataPermission.inviteTableAlias()  + ".invite_user_id" + " IN ( select user_id from distribute_dept_user_role_bind durb_x where dept_id in " +
                                        "(select DISTINCT a_x.dept_id from distribute_dept_info a_x " +
                                        "left join distribute_dept_user_role_bind b_x on a_x.dept_id=b_x.dept_id " +
                                        "where a_x.data_status=1 and b_x.data_status=1 and a_x.distribute_type=2 and a_x.up_level_user_id="+userContext.getUserId()+"))";
                            }

                            expression=new AndExpression(where, CCJSqlParserUtil.parseCondExpression(appendSqlStr));
                        }
                        case SALE_USER_ORDER -> {
                            System.out.println("数据权限拦SALE_USER_ORDER:");
                            String appendSqlStr =null;
                            if (distributeSaleRoleEnum.equals(DistributeSaleRoleEnum.ROLE_DSPD)) {
                                System.out.println("数据权限拦截SALE_USER_ORDER:ROLE_DSPD");
                                 appendSqlStr =dataPermission.orderTableAlias()+".order_id in (select distinct order_id from distribute_order_task_sale " +
                                        " where distribute_user_id= "+userContext.getUserId()+
                                         ")";
                            }else {
                                appendSqlStr =dataPermission.orderTableAlias()+".order_id in (select distinct order_id from distribute_order_task_sale " +
                                        " where distribute_user_id= "+userContext.getUserId()+" and distribute_role_code ='" + distributeSaleRoleEnum.getCode()+
                                        "')";
                            }
                            expression=new AndExpression(where, CCJSqlParserUtil.parseCondExpression(appendSqlStr));
                        }
                        case SALE_DEPT_USER -> {
                            System.out.println("数据权限拦SALE_DEPT_USER:");
                            String appendSqlStr =dataPermission.nodeTableAlias()  + ".user_id" + " IN ( select user_id from distribute_dept_user_role_bind durb_x where dept_id in " +
                                    "(select DISTINCT a_x.dept_id from distribute_dept_info a_x " +
                                    "left join distribute_dept_user_role_bind b_x on a_x.dept_id=b_x.dept_id " +
                                    "where a_x.data_status=1 and b_x.data_status=1 and a_x.distribute_type=2 and a_x.up_level_user_id="+userContext.getUserId()+"))";
                            expression=new AndExpression(where, CCJSqlParserUtil.parseCondExpression(appendSqlStr));
                        }
                        default -> throw new IllegalArgumentException("暂不支持 [%s] 数据权限".formatted(dataPermission.dataScope()));
                    }
                }else {
                    throw new IllegalArgumentException("推广数据权限参数错误：暂不支持 [%s] 数据权限".formatted(dataPermission.dataScope()));
                }
                return expression;
            }
            if (dataPermission.distributeType()!=null&&dataPermission.distributeType().equals("1")&& StrUtil.isNotBlank(userContext.getDistributeContentRoleCode())){
                System.out.println("内容分销================================================:");
                DistributeContentRoleEnum distributeContentRoleEnum = DistributeContentRoleEnum.getByCode(userContext.getDistributeContentRoleCode());
            }

        }else{
            System.out.println("数据权限拦截失败：userContext null:");
        }
        return where;
    }

    /**
     * 构建本部门及以下数据权限表达式
     *
     * <p>
     * 处理完后的 SQL 示例：<br /> select t1.* from table as t1 where t1.dept_id in (select id from sys_dept where id = xxx or
     * find_in_set(xxx, ancestors));
     * </p>
     *
     * @param dataPermission 数据权限
     * @param userContext    用户上下文
     * @param expression     处理前的表达式
     * @return 处理完后的表达式
     */
    private Expression buildDeptAndChildExpression(DataPermission dataPermission,
                                                   UserContext userContext,
                                                   Expression expression) {
        ParenthesedSelect subSelect = new ParenthesedSelect();
        PlainSelect select = new PlainSelect();
        select.setSelectItems(Collections.singletonList(new SelectItem<>(new Column(dataPermission.id()))));
        select.setFromItem(new Table(dataPermission.deptTableAlias()));

        EqualsTo equalsTo = new EqualsTo();
        equalsTo.setLeftExpression(new Column(dataPermission.id()));
        equalsTo.setRightExpression(new LongValue(userContext.getDeptId()));

        DatabaseType databaseType = MetaUtils.getDatabaseType(dataSource);
        Expression inSetExpression;
        if (DatabaseType.MYSQL.getDatabase().equalsIgnoreCase(databaseType.getDatabase())) {
            Function findInSetFunction = new Function();
            findInSetFunction.setName("find_in_set");
            findInSetFunction.setParameters(new ExpressionList<>(new LongValue(userContext
                    .getDeptId()), new StringValue(new Column("ancestors") + ",")));
            inSetExpression = findInSetFunction;
        } else {
            throw new IllegalArgumentException("暂不支持 [%s] 数据权限".formatted(""));
        }

        select.setWhere(new OrExpression(equalsTo, inSetExpression));
        subSelect.setSelect(select);
        // 构建父查询
        InExpression inExpression = new InExpression();
        inExpression.setLeftExpression(this.buildColumn(dataPermission.tableAlias(), dataPermission.deptId()));
        inExpression.setRightExpression(subSelect);
        return expression != null ? new OrExpression(expression, inExpression) : inExpression;
    }

    /**
     * 构建本部门数据权限表达式
     *
     * <p>
     * 处理完后的 SQL 示例：<br /> select t1.* from table as t1 where t1.dept_id = xxx;
     * </p>
     *
     * @param dataPermission 数据权限
     * @param userContext    用户上下文
     * @param expression     处理前的表达式
     * @return 处理完后的表达式
     */
    private Expression buildDeptExpression(DataPermission dataPermission,
                                           UserContext userContext,
                                           Expression expression) {
        EqualsTo equalsTo = new EqualsTo();
        equalsTo.setLeftExpression(this.buildColumn(dataPermission.tableAlias(), dataPermission.deptId()));
        equalsTo.setRightExpression(new LongValue(userContext.getDeptId()));
        return expression != null ? new OrExpression(expression, equalsTo) : equalsTo;
    }

    /**
     * 构建仅本人数据权限表达式
     *
     * <p>
     * 处理完后的 SQL 示例：<br /> select t1.* from table as t1 where t1.create_user = xxx;
     * </p>
     *
     * @param dataPermission 数据权限
     * @param userContext    用户上下文
     * @param expression     处理前的表达式
     * @return 处理完后的表达式
     */
    private Expression buildSelfExpression(DataPermission dataPermission,
                                           UserContext userContext,
                                           Expression expression) {
        EqualsTo equalsTo = new EqualsTo();
        equalsTo.setLeftExpression(this.buildColumn(dataPermission.tableAlias(), dataPermission.userId()));
        equalsTo.setRightExpression(new LongValue(userContext.getUserId()));
        return expression != null ? new OrExpression(expression, equalsTo) : equalsTo;
    }

    /**
     * 构建自定义数据权限表达式
     *
     * <p>
     * 处理完后的 SQL 示例：<br /> select t1.* from table as t1 where t1.dept_id in (select dept_id from sys_role_dept where
     * role_id = xxx);
     * </p>
     *
     * @param dataPermission 数据权限
     * @param roleContext    角色上下文
     * @param expression     处理前的表达式
     * @return 处理完后的表达式
     */
    private Expression buildCustomExpression(DataPermission dataPermission,
                                             RoleContext roleContext,
                                             Expression expression) {
        ParenthesedSelect subSelect = new ParenthesedSelect();
        PlainSelect select = new PlainSelect();
        select.setSelectItems(Collections.singletonList(new SelectItem<>(new Column(dataPermission.deptId()))));
        select.setFromItem(new Table(dataPermission.roleDeptTableAlias()));
        EqualsTo equalsTo = new EqualsTo();
        equalsTo.setLeftExpression(new Column(dataPermission.roleId()));
        equalsTo.setRightExpression(new LongValue(roleContext.getRoleId()));
        select.setWhere(equalsTo);
        subSelect.setSelect(select);
        // 构建父查询
        InExpression inExpression = new InExpression();
        inExpression.setLeftExpression(this.buildColumn(dataPermission.tableAlias(), dataPermission.deptId()));
        inExpression.setRightExpression(subSelect);
        return expression != null ? new OrExpression(expression, inExpression) : inExpression;
    }

    /**
     * 构建 Column
     *
     * @param tableAlias 表别名
     * @param columnName 字段名称
     * @return 带表别名字段
     */
    private Column buildColumn(String tableAlias, String columnName) {
        if (StringUtils.isNotEmpty(tableAlias)) {
            return new Column("%s.%s".formatted(tableAlias, columnName));
        }
        return new Column(columnName);
    }
}
